home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
aminet
/
util
/
edit
/
jed207.lha
/
src
/
jed.lha
/
io.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-05
|
17KB
|
790 lines
/*
* IO.C
* (c) 1992-3 J.Harper
*
* functions for loading files, reading clips, etc
*/
#include "jed.h"
#include "jed_protos.h"
Prototype BOOL readtx (TX *, STRPTR, LONG);
Prototype BOOL writetx (TX *, VW *, STRPTR);
Prototype VALUE * cmd_openfile (LONG, VALUE *);
Prototype VALUE * cmd_savefileas (LONG, VALUE *);
Prototype VALUE * cmd_savefile (LONG, VALUE *);
Prototype VALUE * cmd_savesection (LONG, VALUE *);
Prototype VOID doserror (VOID);
Prototype VALUE * cmd_cd (LONG, VALUE *);
Prototype VOID killclipstuff (VOID);
Prototype BOOL writeclip (LONG, POS *, POS *);
Prototype STRPTR readclip (LONG);
Prototype BOOL writeline (STRPTR, WORD, BPTR, VW *);
Local BOOL dobackup (STRPTR, VW *);
/* bytes to copy instead of tabs */
Prototype const UBYTE Spaces[];
Prototype const UBYTE Tabs[];
const UBYTE Spaces[] = " "
" "
" ";
const UBYTE Tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
/*
* read a file into a tx structure, the line list should have been
* killed.
* I'm going to have to speed this up somehow.
* hopefully now loads lines of any length (upto max of 32768)
*/
#define SIZESTEP 50 /* size at which line list grows by */
#define BUFFSTART 1024
BOOL
readtx(TX *tx, STRPTR fileName, LONG diskTab)
{
BOOL rc = FALSE;
BPTR fh;
if(fileName && (*fileName) && (fh = Open(fileName, MODE_OLDFILE)))
{
STRPTR buff;
ULONG bufflen = BUFFSTART;
tx->tx_FileName = savestring(fileName);
tx->tx_TitleName = savestring(FilePart(fileName));
if(buff = AllocVec(bufflen, 0L))
{
LONG c, i = 0;
LONG linenum = 0, allocedlines = 0;
settitle("loading...");
while((c = FGetC(fh)) != -1)
{
if(i >= bufflen)
{
if(i >= 32768)
{
settitle("error: line too long (>32768)");
goto abort;
}
STRPTR newbuff = AllocVec(bufflen << 1, 0L);
if(!newbuff)
goto abortmem;
memcpy(newbuff, buff, i);
FreeVec(buff);
buff = newbuff;
bufflen <<= 1;
}
if(c == '\n')
{
STRPTR newstr;
LINE *line;
if(linenum >= allocedlines)
{
if(!resizelinelist(tx, SIZESTEP, linenum))
goto abortmem;
allocedlines += SIZESTEP;
}
if(!(newstr = AllocVec(i + 1, 0L)))
goto abortmem;
memcpy(newstr, buff, i);
newstr[i] = 0;
line = tx->tx_Lines + linenum;
line->ln_Strlen = i + 1;
line->ln_Line = newstr;
i = 0;
linenum++;
}
else if(c == '\t')
{
WORD numspaces = diskTab - (i % diskTab);
if(i + numspaces >= bufflen)
{
STRPTR newbuff = AllocVec(bufflen << 1, 0L);
if(!newbuff)
goto abortmem;
memcpy(newbuff, buff, i);
FreeVec(buff);
buff = newbuff;
bufflen <<= 1;
}
strncpy(buff + i, Spaces, numspaces);
i += numspaces;
}
else
buff[i++] = c;
}
if(i)
{
STRPTR newstr;
LINE *line;
if(!resizelinelist(tx, linenum - allocedlines + 1, linenum))
goto abortmem;
if(!(newstr = AllocVec(i + 1, 0L)))
goto abortmem;
memcpy(newstr, buff, i);
newstr[i] = 0;
line = tx->tx_Lines + linenum;
line->ln_Strlen = i + 1;
line->ln_Line = newstr;
linenum++;
}
else
if(!resizelinelist(tx, linenum - allocedlines, linenum))
goto abortmem;
tx->tx_Changes = 0;
rc = TRUE;
settitle("OK");
/* This block only gets executed if we aborted while
* reading the file.
*/
if(0)
{
abortmem:
settitle(NoMemMsg);
abort:
clearlinelist(tx);
}
FreeVec(buff);
}
else
settitle(NoMemMsg);
Close(fh);
}
else
{
if(fileName && (*fileName))
{
tx->tx_FileName = savestring(fileName);
tx->tx_TitleName = savestring(FilePart(fileName));
}
else
{
tx->tx_FileName = savestring("");
tx->tx_TitleName = savestring("Untitled");
}
tx->tx_Changes = 0;
if(clearlinelist(tx))
rc = TRUE;
else
settitle(NoMemMsg);
}
return(rc);
}
BOOL
writetx(TX *tx, VW *vw, STRPTR fileName)
{
BOOL rc = TRUE;
if(fileName)
{
BPTR fh = Open(fileName, MODE_NEWFILE);
if(fh)
{
LONG i;
LINE *line = tx->tx_Lines;
settitle("saving...");
for(i = 0; i < tx->tx_NumLines; i++, line++)
{
if(!writeline(line->ln_Line, line->ln_Strlen - 1, fh, vw))
{
doserror();
rc = FALSE;
break;
}
FPutC(fh, '\n');
}
Close(fh);
}
else
{
doserror();
rc = FALSE;
}
if(rc)
settitle("OK");
}
else
{
settitle(NoMemMsg);
rc = FALSE;
}
return(rc);
}
/*
* (openfile `fileName')
*/
VALUE *
cmd_openfile(LONG argc, VALUE *argv)
{
if(TPLATE1(VTF_STRING))
{
VW *vw = CurrVW;
TX *tx = vw->vw_Tx;
BOOL rc = FALSE;
if((!tx->tx_Changes) || (ezreq("OK to lose %ld changes\nto file %s", "Yeah|Cancel", tx->tx_Changes, tx->tx_TitleName)))
{
killlinelist(tx);
freestring(tx->tx_FileName);
freestring(tx->tx_TitleName);
if(readtx(tx, ARG1.val_Value.String, vw->vw_Prefs.prf_DiskTab))
rc = TRUE;
else
clearlinelist(tx); /* hope for some mem left */
setupfileprefs(tx);
updatedimensions(vw);
resetallviews(tx);
}
resetslptxtitles(tx);
setnumres(rc);
}
return(&RES);
}
/*
* (savefileas `fileName')
*/
VALUE *
cmd_savefileas(LONG argc, VALUE *argv)
{
if(TPLATE1(VTF_STRING))
{
TX *tx = CurrVW->vw_Tx;
BOOL rc = FALSE;
dobackup(ARG1.val_Value.String, CurrVW);
if(writetx(tx, CurrVW, ARG1.val_Value.String))
{
freestring(tx->tx_FileName);
freestring(tx->tx_TitleName);
tx->tx_FileName = savestring(ARG1.val_Value.String);
tx->tx_TitleName = savestring(FilePart(ARG1.val_Value.String));
tx->tx_Changes = 0;
savefileprefs(tx);
rc = TRUE;
}
resetslptxtitles(tx);
setnumres(rc);
}
return(&RES);
}
/*
* (savefile)
*/
VALUE *
cmd_savefile(LONG argc, VALUE *argv)
{
TX *tx = CurrVW->vw_Tx;
BOOL rc = FALSE;
if(tx->tx_FileName && tx->tx_FileName[0])
{
dobackup(tx->tx_FileName, CurrVW);
if(writetx(tx, CurrVW, tx->tx_FileName))
{
tx->tx_Changes = 0;
savefileprefs(tx);
rc = TRUE;
}
}
else
settitle("error: file is untitled");
setnumres(rc);
return(&RES);
}
/*
* (savesection `sectionType' `fileName')
*/
VALUE *
cmd_savesection(LONG argc, VALUE *argv)
{
if(TPLATE2(VTF_STRING, VTF_STRING))
{
VW *vw = CurrVW;
POS endpos;
POS oldcurs = vw->vw_CursorPos;
BOOL rc = TRUE;
padcursor();
if(getsection(ARG1.val_Value.String, &endpos))
{
BPTR fh = Open(ARG2.val_Value.String, MODE_NEWFILE);
if(fh)
{
LINE *line = vw->vw_Tx->tx_Lines + vw->vw_CursorPos.pos_Line;
if(endpos.pos_Line == vw->vw_CursorPos.pos_Line)
{
if(!writeline(line->ln_Line + vw->vw_CursorPos.pos_Col, endpos.pos_Col - vw->vw_CursorPos.pos_Col, fh, vw))
{
doserror();
rc = FALSE;
}
}
else
{
if(vw->vw_CursorPos.pos_Col)
{
if(!writeline(line->ln_Line + vw->vw_CursorPos.pos_Col, line->ln_Strlen - vw->vw_CursorPos.pos_Col - 1, fh, vw))
goto writeerr;
FPutC(fh, '\n');
vw->vw_CursorPos.pos_Line++;
line++;
}
while(vw->vw_CursorPos.pos_Line < endpos.pos_Line)
{
if(!writeline(line->ln_Line, line->ln_Strlen - 1, fh, vw))
goto writeerr;
FPutC(fh, '\n');
vw->vw_CursorPos.pos_Line++;
line++;
}
if(endpos.pos_Col)
{
if(!writeline(line->ln_Line, endpos.pos_Col, fh, vw))
{
writeerr: doserror();
rc = FALSE;
}
}
}
Close(fh);
}
else
{
doserror();
rc = FALSE;
}
}
vw->vw_CursorPos = oldcurs;
setnumres(rc);
}
return(&RES);
}
/*
* Sets title bar to message describing previous DOS error.
*/
VOID
doserror(VOID)
{
UBYTE errmsg[81];
if(Fault(IoErr(), "DOS error", errmsg, 81))
settitle(errmsg);
else
settitlefmt("DOS error: %ld", IoErr());
}
/*
* (cd `dir')
*/
VALUE *
cmd_cd(LONG argc, VALUE *argv)
{
if(TPLATE1(VTF_STRING))
{
BOOL rc = FALSE;
BPTR lock = Lock(ARG1.val_Value.String, SHARED_LOCK);
if(lock)
{
lock = CurrentDir(lock);
UnLock(lock);
rc = TRUE;
}
else
settitlefmt("can't lock %s", (LONG)ARG1.val_Value.String);
setnumres(rc);
}
return(&RES);
}
/*
* IFF code, adapted from the newiff/other/clipftxt.c example on the 2.0
* native developer set.
*/
#define ID_FTXT MAKE_ID('F','T','X','T')
#define ID_CHRS MAKE_ID('C','H','R','S')
Local const STRPTR IFFErrorMsgs[] =
{
"End of file.",
"End of context.",
"No lexical scope.",
"No memory.",
"Stream read error.",
"Stream write error.",
"Stream seek error.",
"File is corrupt.",
"IFF syntax error.",
"Not an IFF file.",
"Required call-back hook missing.",
"Return to client."
};
APTR IFFParseBase;
Local STRPTR InternalClip;
Local LONG IClipLen; /* not including zero terminator */
VOID
killclipstuff(VOID)
{
freestring(InternalClip);
InternalClip = NULL;
IClipLen = 0;
if(IFFParseBase)
{
CloseLibrary(IFFParseBase);
IFFParseBase = NULL;
}
}
/*
* Writes a section of text to the clipboard, *startPos IS trashed (it will
* point to the end of the copied section (maybe)).
* if unit is less than 0 the text is copied to my internal clipboard.
*/
BOOL
writeclip(LONG unit, POS *startPos, POS *endPos)
{
if(unit < 0)
{
IClipLen = sectionlength(startPos, endPos);
freestring(InternalClip);
if(InternalClip = AllocVec(IClipLen + 1, 0L))
{
copysection(startPos, endPos, InternalClip);
InternalClip[IClipLen] = 0;
return(TRUE);
}
settitle(NoMemMsg);
return(FALSE);
}
else if(IFFParseBase || (IFFParseBase = OpenLibrary("iffparse.library", 36)))
{
struct IFFHandle *iff;
LONG error = 0;
if(iff = AllocIFF())
{
if(iff->iff_Stream = (ULONG)OpenClipboard(unit))
{
InitIFFasClip(iff);
if(!(error = OpenIFF(iff, IFFF_WRITE)))
{
if(!(error = PushChunk(iff, ID_FTXT, ID_FORM, IFFSIZE_UNKNOWN)))
{
if(!(error = PushChunk(iff, 0, ID_CHRS, IFFSIZE_UNKNOWN)))
{
LINE *line = CurrVW->vw_Tx->tx_Lines + startPos->pos_Line;
LONG writelen;
if(endPos->pos_Line == startPos->pos_Line)
{
writelen = endPos->pos_Col - startPos->pos_Col;
if(WriteChunkBytes(iff, line->ln_Line + startPos->pos_Col, writelen) != writelen)
error = IFFERR_WRITE;
}
else
{
if(startPos->pos_Col)
{
writelen = line->ln_Strlen - startPos->pos_Col - 1;
if(WriteChunkBytes(iff, line->ln_Line + startPos->pos_Col, writelen) != writelen)
goto writeerr;
if(WriteChunkBytes(iff, "\n", 1) != 1)
goto writeerr;
startPos->pos_Line++;
line++;
}
while(startPos->pos_Line < endPos->pos_Line)
{
writelen = line->ln_Strlen - 1;
if(WriteChunkBytes(iff, line->ln_Line, writelen) != writelen)
goto writeerr;
if(WriteChunkBytes(iff, "\n", 1) != 1)
goto writeerr;
startPos->pos_Line++;
line++;
}
if(endPos->pos_Col)
{
writelen = endPos->pos_Col;
if(WriteChunkBytes(iff, line->ln_Line, writelen) != writelen)
{
writeerr:
error = IFFERR_WRITE;
}
}
}
if(!error)
error = PopChunk(iff);
else
PopChunk(iff);
}
if(!error)
error = PopChunk(iff);
else
PopChunk(iff);
}
CloseIFF(iff);
}
CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
}
else
error = IFFERR_NOMEM; /* ?? */
FreeIFF(iff);
}
else
error = IFFERR_NOMEM;
CloseLibrary(IFFParseBase);
IFFParseBase = NULL;
if(error)
{
settitlefmt("clip error: %s", (LONG)IFFErrorMsgs[-error - 1]);
return(FALSE);
}
return(TRUE);
}
settitle("need iffparse.library");
return(FALSE);
}
/*
* result should be FreeVec()'ed after use if non-NULL. A unit of -1
* reads the internal clip.
*
* note:
* Currently this only reads the first CHRS chunk that it finds.
*/
STRPTR
readclip(LONG unit)
{
STRPTR text = NULL;
if(unit < 0)
{
if(IClipLen)
{
if(text = AllocVec(IClipLen + 1, 0L))
{
memcpy(text, InternalClip, IClipLen);
text[IClipLen] = 0;
}
else
settitle(NoMemMsg);
}
else
settitle("error: nothing on internal clipboard");
}
else if(IFFParseBase || (IFFParseBase = OpenLibrary("iffparse.library", 36)))
{
struct IFFHandle *iff;
LONG error;
if(iff = AllocIFF())
{
if(iff->iff_Stream = (ULONG)OpenClipboard(unit))
{
InitIFFasClip(iff);
if(!(error = OpenIFF(iff, IFFF_READ)))
{
if(!(error = StopChunk(iff, ID_FTXT, ID_CHRS)))
{
struct ContextNode *cn;
if(!(error = ParseIFF(iff, IFFPARSE_SCAN)))
{
cn = CurrentChunk(iff);
if(cn && (cn->cn_Type == ID_FTXT) && (cn->cn_ID == ID_CHRS))
{
if(text = AllocVec(cn->cn_Size + 1, 0L))
{
error = ReadChunkBytes(iff, text, cn->cn_Size);
if(error > 0)
{
text[error] = 0;
error = 0;
}
}
else
error = IFFERR_NOMEM;
}
else
error = IFFERR_NOTIFF; /* ?? */
}
}
CloseIFF(iff);
}
CloseClipboard((struct ClipboardHandle *)iff->iff_Stream);
}
else
error = IFFERR_NOMEM;
FreeIFF(iff);
}
else
error = IFFERR_NOMEM;
if(error)
{
if(text)
{
FreeVec(text);
text = NULL;
}
settitlefmt("clip error: %s", (LONG)IFFErrorMsgs[-error - 1]);
}
CloseLibrary(IFFParseBase);
IFFParseBase = NULL;
}
else
settitle("need iffparse.library");
return(text);
}
/*
* Writes out a line of text,
* if SaveTabs == 1 leading spaces will be changed to tabs,
* if SaveTabs == 2 all spaces (except after quotes) are made into tabs and
* trailing spaces are discarded.
*/
BOOL
writeline(STRPTR line, WORD len, BPTR fh, VW *vw)
{
if(vw->vw_Prefs.prf_SaveTabs)
{
WORD lastchg = 0;
BOOL inspc = FALSE;
BOOL nodo = FALSE;
LONG disktab = vw->vw_Prefs.prf_DiskTab;
WORD i;
UBYTE c;
for(i = 0; (i <= len) && (c = line[i]); i++)
{
if(!nodo)
{
if(c == ' ')
{
if(!inspc)
{
if(FWrite(fh, line + lastchg, 1, i - lastchg) != i - lastchg)
goto error;
lastchg = i;
inspc = TRUE;
}
}
else
{
if(inspc)
{
WORD numtabs, numspcs;
if(lastchg == i - 1)
{
numtabs = 0;
numspcs = 1;
}
else
{
numtabs = (i - (lastchg - (lastchg % disktab))) / disktab;
numspcs = i % disktab;
if(numspcs > i - lastchg)
numspcs = i - lastchg;
}
if(FWrite(fh, Tabs, 1, numtabs) != numtabs)
goto error;
if(FWrite(fh, Spaces, 1, numspcs) != numspcs)
goto error;
lastchg = i;
inspc = FALSE;
}
if((c == '"') || (c == '\'') || (c == '`') || (vw->vw_Prefs.prf_SaveTabs == 1))
nodo = TRUE;
}
}
}
if((!inspc) || nodo)
{
if(FWrite(fh, line + lastchg, 1, i - lastchg) != i - lastchg)
goto error;
}
return(TRUE);
}
else
{
if(FWrite(fh, line, 1, len) == len)
return(TRUE);
}
error:
return(FALSE);
}
/*
* Sorts out backup files.
* Backups are saved to the directory set by (setpref `bakdir'). The
* number of backups kept is determined by (setpref `baknum').
* for a file called `foo' it's backups would be something like this,
* t:foo.bak1
* t:foo.bak2
* t:foo.bakN
*/
#define COPYSTEP 65536
Local BOOL
dobackup(STRPTR fileName, VW *vw)
{
BOOL rc = TRUE;
if(vw->vw_Prefs.prf_MaxBak > 0)
{
UBYTE namebuff[110];
WORD i;
BPTR srcfh = 0, dstfh = 0;
strcpy(namebuff, vw->vw_Prefs.prf_BakDir);
if(AddPart(namebuff, FilePart(fileName), 100))
{
for(i = vw->vw_Prefs.prf_MaxBak - 1; i; i--)
{
UBYTE srcbuff[110];
UBYTE dstbuff[110];
sprintf(srcbuff, "%s.bak%ld", namebuff, i);
sprintf(dstbuff, "%s.bak%ld", namebuff, i + 1);
DeleteFile(dstbuff);
Rename(srcbuff, dstbuff);
}
}
else
{
settitle("error: backup directory name too long");
return(FALSE);
}
strcat(namebuff, ".bak1");
if((srcfh = Open(fileName, MODE_OLDFILE)) && (dstfh = Open(namebuff, MODE_NEWFILE)))
{
STRPTR copybuff;
if(copybuff = AllocVec(COPYSTEP, 0L))
{
LONG actual;
do
{
if((actual = Read(srcfh, copybuff, COPYSTEP)) < 0)
{
doserror();
rc = FALSE;
break;
}
if(Write(dstfh, copybuff, actual) != actual)
{
doserror();
rc = FALSE;
break;
}
}
while(actual == COPYSTEP);
FreeVec(copybuff);
}
else
{
settitle(NoMemMsg);
rc = FALSE;
}
}
if(dstfh)
Close(dstfh);
if(srcfh)
Close(srcfh);
}
return(rc);
}